package org.xiaoxin.onecoupon.framework.idempotent;

import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson2.JSON;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.xiaoxin.onecoupon.framework.exception.ClientException;

import java.lang.reflect.Method;

/**
 * 防止用户重复提交表单信息切面控制器
 * @author xiaoxin
 * 2025/4/17
 */
@RequiredArgsConstructor
@Aspect
public final class NoDuplicateSubmitAspect {
    private  final RedissonClient redissonClient;
    @Around("@annotation(org.xiaoxin.onecoupon.framework.idempotent.NoDuplicateSubmit)")
    public  Object noDuplicateSubmit(ProceedingJoinPoint joinPoint)  throws  Throwable{
        //获取注解实例
        NoDuplicateSubmit noDuplicateSubmit=getNoDuplicateSubmitAnnotation(joinPoint);
        //获取分布式锁标识
        String lockKey = String.format("no-duplicate-submit:path:%s:currentUserId:%s:md5:%s", getServletPath(), getCurrentUserId(), calcArgsMD5(joinPoint));
        RLock lock = redissonClient.getLock(lockKey);
        if (!lock.tryLock()){
            throw new ClientException(noDuplicateSubmit.message());
        }
        Object result;
        try {
            result=joinPoint.proceed();
        }finally {
            lock.unlock();
        }
        return  result;
    }
    /**
     * @return 返回自定义防重复提交注解
     */
    public static NoDuplicateSubmit getNoDuplicateSubmitAnnotation(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
        //获取目标方法的签名
        MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
        //获取目标方法的Method对象。
        Method targetMethod = joinPoint.getTarget().getClass().getDeclaredMethod(methodSignature.getName(),methodSignature.getMethod().getParameterTypes());
        //获取注解实例
        return targetMethod.getAnnotation(NoDuplicateSubmit.class);


    }
    /**
     * @return 获取当前线程上下文 ServletPath
     */
    private String getServletPath() {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return sra.getRequest().getServletPath();
    }

    /**
     * @return 当前操作用户 ID
     */
    private String getCurrentUserId() {
        // 用户属于非核心功能，这里先通过模拟的形式代替。后续如果需要后管展示，会重构该代码
        return "1810518709471555585";
    }

    /**
     * @return joinPoint md5
     */
    private String calcArgsMD5(ProceedingJoinPoint joinPoint) {
        return DigestUtil.md5Hex(JSON.toJSONBytes(joinPoint.getArgs()));
    }
}
